package com.bobo.base.quartz;

import com.bobo.pojo.SysJob;
import com.bobo.util.DateUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.Objects;

/**
 * 定时任务调度
 *
 * @author LILIBO
 * @since 2021-06-24
 */
@Slf4j
@Component
public class QuartzJobScheduler {

    @Resource
    private Scheduler scheduler;

    /**
     * 构建任务触发对象
     */
    public static TriggerKey getTriggerKey(Long jobId, String jobGroup) {
        return TriggerKey.triggerKey(QuartzConstants.TASK_CLASS + jobId, jobGroup);
    }

    /**
     * 构建任务键对象
     */
    public static JobKey getJobKey(Long jobId, String jobGroup) {
        return JobKey.jobKey(QuartzConstants.TASK_CLASS + jobId, jobGroup);
    }

    /**
     * 清空所有定时任务
     */
    public boolean clear() {
        try {
            scheduler.clear();
            log.debug("Scheduler Clear Success.");
        } catch (SchedulerException e) {
            log.error("Scheduler Clear Error ", e);
            return false;
        }
        return true;
    }

    /**
     * 创建简单的定时任务（在时间范围内每隔n秒执行一次）
     *
     * @param job 定时任务
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param interval 时间间隔
     */
    public boolean createSimpleJob(SysJob job, Date startTime, Date endTime, int interval) {
        // 构建任务键对象
        JobKey jobKey = getJobKey(job.getId(), job.getJobGroup());
        // 构建触发器键对象
        TriggerKey triggerKey = getTriggerKey(job.getId(), job.getJobGroup());
        // 构建工作任务信息
        JobDetail jobDetail = JobBuilder.newJob(QuartzJobExecution.class).withIdentity(jobKey).build();

        SimpleTrigger simpleTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).startAt(startTime).endAt(endTime).withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(interval).repeatForever()).build();
        try {
            // 调度任务,并获取下一次执行时间
            Date date = scheduler.scheduleJob(jobDetail, simpleTrigger);

            // 成功时输出下一次执行时间
            log.debug("Create Simple Job Schedule Success. {}", (date != null ? "Next Execution Time: " + DateUtil.format("yyyy-MM-dd HH:mm:ss", date) : "Job is Over."));
        } catch (SchedulerException e) {
            log.error("Create Simple Job Schedule Failure: ", e);
            return false;
        }
        return true;
    }

    /**
     * 安排定时任务（通过Cron表达式定义周期，可修改）
     *
     * @param job 定时任务
     */
    public boolean scheduleJob(SysJob job) {
        // 构建任务键对象
        JobKey jobKey = getJobKey(job.getId(), job.getJobGroup());
        // 构建触发器键对象
        TriggerKey triggerKey = getTriggerKey(job.getId(), job.getJobGroup());

        // 构建工作任务信息
        JobDetail jobDetail = JobBuilder.newJob(QuartzJobExecution.class).withIdentity(jobKey).build();
        // 表达式调度构建器
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
        // 根据新的Cron表达式构建一个新的Trigger
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
        // 设置运行时任务参数
        jobDetail.getJobDataMap().put(QuartzConstants.TASK_PROPERTIES, job);

        try {
            // 任务调度下一次执行时间
            Date date = null;

            // 判断任务是否存在
            if (scheduler.checkExists(jobKey)) {
                // 防止创建时存在数据问题，先移除旧的任务，然后在执行创建操作
                scheduler.deleteJob(jobKey);
            }
            // 判断任务是否过期
            if (QuartzCronUtil.getNextExecution(job.getCronExpression()) != null) {
                // 执行调度任务
                date = scheduler.scheduleJob(jobDetail, trigger);
            }
            // 判断任务是否暂停
            if (Objects.equals(job.getStatus(), QuartzConstants.Status.PAUSE.getValue())) {
                scheduler.pauseJob(jobKey);
                date = null;
            }

            // 成功时输出下一次执行时间
            log.debug("Create Job Schedule Success. {}", (date != null ? "Next Execution Time: " + DateUtil.format("yyyy-MM-dd HH:mm:ss", date) : "Job is Paused."));
        } catch (SchedulerException e) {
            log.error("Create Job Schedule Failure: ", e);
            return false;
        }
        return true;
    }

    /**
     * 重新安排定时任务（通过Cron表达式重新定义周期）
     *
     * @param job 定时任务
     */
    public boolean rescheduleJob(SysJob job) {
        // 构建任务键对象
        JobKey jobKey = getJobKey(job.getId(), job.getJobGroup());
        // 构建触发器键对象
        TriggerKey triggerKey = getTriggerKey(job.getId(), job.getJobGroup());

        // 表达式调度构造器
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
        // 按新的Cron表达式构造一个触发器
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
        try {
            // 任务调度下一次执行时间
            Date date = null;

            // 判断任务是否存在
            if (scheduler.checkExists(jobKey)) {
                // 重新安排任务
                date = scheduler.rescheduleJob(triggerKey, trigger);
            }
            // 判断任务是否暂停
            if (Objects.equals(job.getStatus(), QuartzConstants.Status.PAUSE.getValue())) {
                scheduler.pauseJob(jobKey);
                date = null;
            }

            // 成功时输出下一次执行时间
            log.debug("Reschedule Job Schedule Success. {}", (date != null ? "Next Execution Time: " + DateUtil.format("yyyy-MM-dd HH:mm:ss", date) : "Job is Paused."));
        } catch (SchedulerException e) {
            log.error("Reschedule Job Schedule Failure: ", e);
            return false;
        }
        return true;
    }

    /**
     * 暂停定时任务（暂停已存在的任务）
     *
     * @param job 定时任务
     */
    public boolean pauseJob(SysJob job) {
        // 构建任务键对象
        JobKey jobKey = getJobKey(job.getId(), job.getJobGroup());
        try {
            // 判断任务是否存在
            if (scheduler.checkExists(jobKey)) {
                // 暂停任务
                scheduler.pauseJob(jobKey);
                job.setStatus(QuartzConstants.Status.PAUSE.getValue());
            }
            // 成功时输出提示信息
            log.debug("Pause Job Success.");
        } catch (SchedulerException e) {
            log.error("Pause Job Failure: ", e);
            return false;
        }
        return true;
    }

    /**
     * 恢复定时任务（从暂停状态恢复任务运行）
     *
     * @param job 定时任务
     */
    public boolean resumeJob(SysJob job) {
        // 构建任务键对象
        JobKey jobKey = getJobKey(job.getId(), job.getJobGroup());
        try {
            // 判断任务是否存在
            if (scheduler.checkExists(jobKey)) {
                // 恢复任务
                scheduler.resumeJob(jobKey);
                job.setStatus(QuartzConstants.Status.NORMAL.getValue());
            }
            // 成功时输出提示信息
            log.debug("Resume Job Success.");
        } catch (SchedulerException e) {
            log.error("Resume Job Failure: ", e);
            return false;
        }
        return true;
    }

    /**
     * 删除定时任务（任务将从系统移除）
     *
     * @param job 定时任务
     */
    public boolean deleteJob(SysJob job) {
        // 构建任务键对象
        JobKey jobKey = getJobKey(job.getId(), job.getJobGroup());
        try {
            // 判断任务是否存在
            if (scheduler.checkExists(jobKey)) {
                // 删除任务
                scheduler.deleteJob(jobKey);
            }
            // 成功时输出提示信息
            log.debug("Delete Job Success.");
        } catch (SchedulerException e) {
            log.error("Delete Job Failure: ", e);
            return false;
        }
        return true;
    }

}
